package com.vichat.workflow.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.googlecode.aviator.AviatorEvaluator;
import com.vichat.common.cache.RedisHelper;
import com.vichat.common.util.Configure;
import com.vichat.common.util.DateUtil;
import com.vichat.common.util.NumberUtils;
import com.vichat.common.util.StringUtil;
import com.vichat.common.vo.PageFilter;
import com.vichat.core.dao.BaseDaoI;
import com.vichat.res.entity.ResConfig;
import com.vichat.user.entity.UserBasic;
import com.vichat.workflow.entity.*;
import com.vichat.workflow.service.IWorkflowServcie;
import com.vichat.workflow.service.WorkflowConstant;
import com.vichat.workflow.vo.WorkflowUser;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.util.*;

/**
 * Created by wangluyin on 2018/5/21.
 */
@Service("workflowServcie")
public class WorkflowServcieImpl implements IWorkflowServcie {

    private static transient final Logger logger = LoggerFactory.getLogger(WorkflowServcieImpl.class);
    @Autowired
    private BaseDaoI<Wf> wfDao;

    @Autowired
    private BaseDaoI<WfNode> wfNodeDao;
    @Autowired
    private BaseDaoI<WfNodeAttrFieldset> wfNodeAttrFieldsetDao;
    @Autowired
    private BaseDaoI<WfNodeAttr> wfNodeAttrDao;
    @Autowired
    private BaseDaoI<InsWf> insWfDao;
    @Autowired
    private BaseDaoI<InsWfNode> insWfNodeDao;
    @Autowired
    private BaseDaoI<InsWfNodeAttr> insWfNodeAttrDao;
    @Autowired
    private BaseDaoI<WfSchedule> wfScheduleDao;

    @Autowired
    private BaseDaoI<WfResource> wfResourceDao;

    @Autowired
    private BaseDaoI<WfTempResource> wfTempResourceDao;


    @Autowired
    private BaseDaoI<ResConfig> configDao;

    @Autowired
    private BaseDaoI<UserBasic> userDao;

    /**
     * 获取当前有效工作流程
     *
     * @return
     */
    @Override
    public List<Wf> getWorkflows(long partyId) {
        String sql = "select a.* from wfdb.WF a, wfdb.PARTY_WF_REL b where a.STATE = 1 and a.FLOW_CODE = b.FLOW_CODE and b.PARTY_ID = :partyId";
        HashMap params = new HashMap();
        params.put("partyId", partyId);
        List<Wf> wfs = wfDao.findEntityBySql(sql, params, Wf.class);
        return wfs;
    }

    /**
     * 根据流程编号获取工作流程
     *
     * @param flowId
     * @return
     */
    @Override
    public Wf getWorkflowById(long flowId) {
        return wfDao.get(Wf.class, flowId);
    }

    /**
     * 根据流程编码获取工作流程
     *
     * @param flowCode
     * @return
     */
    public Wf getWorkflowByFlowCode(String flowCode) {
        String hql = "from Wf where state = 1 and flowCode = :flowCode ";
        HashMap params = new HashMap();
        params.put("flowCode", flowCode);
        return wfDao.get(hql, params);
    }

    /**
     * 根据流程编号获取所有流程节点信息
     *
     * @param flowId
     * @return
     */
    @Override
    public List<WfNode> getWfNodesByFlowId(long flowId) {
        String hql = "from WfNode where  flowId = :flowId ";
        HashMap params = new HashMap();
        params.put("flowId", flowId);
        return wfNodeDao.find(hql, params);
    }

    /**
     * 根据流程节点编号获取流程节点信息
     *
     * @param nodeId
     * @return
     */
    @Override
    public WfNode getWfNodeByNodeId(long nodeId) {
        return wfNodeDao.get(WfNode.class, nodeId);
    }

    @Override
    public InsWf getInsFlowById(Long insWfId)throws Exception{return insWfDao.get(InsWf.class,insWfId);}

    @Override
    public InsWf updateInsWfAttr(long insFlowId, String attr1) throws Exception {
        InsWf wf = getInsFlowById(insFlowId);
        wf.setFlowAttr1(attr1);
        insWfDao.save(wf);
        return wf;
    }

    /**
     * 根据流程编号获取开始流程节点信息
     *
     * @param flowId
     * @return
     */
    @Override
    public WfNode getWfStartNode(long flowId) {
        String hql = "from WfNode where  flowId = :flowId and nodeType =:nodeType";
        HashMap params = new HashMap();
        params.put("flowId", flowId);
        params.put("nodeType", "START");
        return wfNodeDao.get(hql, params);
    }


    public List<WfNodeAttrFieldset> getAttrFieldsetByNodeId(long nodeId, long flowId) {
        String hql = "from WfNodeAttrFieldset where  nodeId = :nodeId and flowId = :flowId order by sort ";
        HashMap params = new HashMap();
        params.put("nodeId", nodeId);
        params.put("flowId", flowId);
        return wfNodeAttrFieldsetDao.find(hql, params);
    }

    public List<WfNodeAttr> getAttrsByFieldsetId(long nodeId, long fieldsetId) {
        String hql = "from WfNodeAttr where  nodeId = :nodeId and fieldsetId= :fieldsetId order by sort";
        HashMap params = new HashMap();
        params.put("nodeId", nodeId);
        params.put("fieldsetId", fieldsetId);
        return wfNodeAttrDao.find(hql, params);
    }

    public List<WfNodeAttr> getAttrsByNodeId(long nodeId) {
        String hql = "from WfNodeAttr where  nodeId = :nodeId ";
        HashMap params = new HashMap();
        params.put("nodeId", nodeId);
        return wfNodeAttrDao.find(hql, params);
    }


    private WfSchedule getWfSchedule(long insFlowId, long insNodeId) {
        String hql = "from WfSchedule where insFlowId= :insFlowId and insNodeId =:insNodeId";
        HashMap params = new HashMap();
        params.put("insFlowId", insFlowId);
        params.put("insNodeId", insNodeId);
        return wfScheduleDao.get(hql, params);
    }

    public List<InsWfNodeAttr> getInsAttrsByInsFlowId(long insFlowId) {
        String hql = "from InsWfNodeAttr where insFlowId= :insFlowId  ";
        HashMap params = new HashMap();
        params.put("insFlowId", insFlowId);
        return insWfNodeAttrDao.find(hql, params);
    }

    public List<InsWfNodeAttr> getInsAttrsByInsNodeId(long insNodeId) {
        String hql = "from InsWfNodeAttr where insNodeId= :insNodeId  ";
        HashMap params = new HashMap();
        params.put("insNodeId", insNodeId);
        return insWfNodeAttrDao.find(hql, params);
    }

    public InsWf getInsWfById(long insFlowId) {
        String hql = "from InsWf where  insFlowId = :insFlowId";
        HashMap params = new HashMap();
        params.put("insFlowId", insFlowId);
        return insWfDao.get(hql, params);
    }

    public InsWfNode getInsWfNodeById(long insNodeId) {
        String hql = "from InsWfNode where  insNodeId = :insNodeId";
        HashMap params = new HashMap();
        params.put("insNodeId", insNodeId);
        return insWfNodeDao.get(hql, params);
    }


    public InsWfNodeAttr getInsWfAttrByInsFlowId(long insFlowId) {
        String hql = "from InsWfNodeAttr where  insFlowId = :insFlowId and insNodeId = -1";
        HashMap params = new HashMap();
        params.put("insNodeId", insFlowId);
        return insWfNodeAttrDao.get(hql, params);
    }

    /**
     * 开始流程
     *
     * @param wf
     * @param node
     * @param models
     * @param user
     * @return
     * @throws Exception
     */
    public InsWf startFlow(Wf wf, WfNode node, Map<String, Object> models, WorkflowUser user) throws Exception {
        //流程实例
        InsWf insWf = new InsWf();
        BeanUtils.copyProperties(insWf, wf);
        insWf.setFlowState(WorkflowConstant.FLOW_STATE_TODO);
        insWf.setCreateUid(user.getUid());
        insWf.setCreateUname(RedisHelper.getUname(user.getUid()));
        insWf.setPartyId(user.getPartyId());
        insWfDao.save(insWf);
        List<String> attrKeyList = new ArrayList<>();
        //流程节点实例
        InsWfNode insWfNode = genNextInsNode(insWf, node, true, user.getUid(), user.getUid());

        insWfNode.setDealUid(insWf.getCreateUid());
        insWfNode.setDealUname(RedisHelper.getUname(insWf.getCreateUid()));
        insWfNode.setDealTime(DateUtil.getCalendarCurrentTimestamp());
        insWfNodeDao.update(insWfNode);

        //流程属性
        List<WfNodeAttr> attrs = getAttrsByNodeId(node.getNodeId());

        for (WfNodeAttr attr : attrs) {
            if (models.containsKey(attr.getAttrCode())) {

                String attrValue = getNodeAttrValue(attr, models);
                if ("upload".equalsIgnoreCase(attr.getAttrType())) {
                    //获取附件信息
                    JSONArray attrJsonObj = JSON.parseArray(attrValue);
                    if (attrJsonObj != null && !attrJsonObj.isEmpty()) {
                        JSONArray wfResorces = new JSONArray();
                        for (int i = 0; i < attrJsonObj.size(); i++) {
                            if (attrJsonObj != null && attrJsonObj.getJSONObject(i).containsKey("storeSrc") && "TEMP_LOCAL".equals(attrJsonObj.getJSONObject(i).getString("storeSrc"))) {//这里肯定是 TEMP_LOCAL
                                WfTempResource wfTempResource = JSONObject.toJavaObject(attrJsonObj.getJSONObject(i), WfTempResource.class);
                                WfResource wfResource = moveTempFileToFileStore(wfTempResource, attr, insWfNode);//处理文件
                                wfResorces.add(wfResource);
                            }
                        }
                        attrValue = wfResorces.toJSONString();
                    }

                }


                InsWfNodeAttr insWfNodeAttr = new InsWfNodeAttr();
                BeanUtils.copyProperties(insWfNodeAttr, attr);
                insWfNodeAttr.setInsFlowId(insWf.getInsFlowId());
                insWfNodeAttr.setAttrValue(attrValue);
                insWfNodeAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                insWfNodeAttr.setAttrName(attr.getAttrName());
                insWfNodeAttr.setAttrCode(attr.getAttrCode());
                insWfNodeAttr.setInsNodeId(insWfNode.getInsNodeId());
                insWfNodeAttrDao.save(insWfNodeAttr);

                if (attr.getIsNodeAttr() != null && "N".equalsIgnoreCase(attr.getIsNodeAttr())) {
                    InsWfNodeAttr insWfAttr = new InsWfNodeAttr();
                    BeanUtils.copyProperties(insWfAttr, insWfNodeAttr);
                    insWfAttr.setFlowId(-1L);
                    insWfAttr.setFieldsetId(-1L);
                    insWfAttr.setNodeId(-1L);
                    insWfAttr.setInsNodeId(-1L);
                    insWfAttr.setAttrValue(attrValue);
                    insWfNodeAttrDao.save(insWfAttr);
                }
                //流程关键字
                if (StringUtils.isNotBlank(attr.getAttrExp())) {
                    JSONObject json = JSON.parseObject(attr.getAttrExp());
                    if (StringUtils.isNotBlank(json.getString("isAttrKey"))) {
                        if (StringUtil.stringToBoolean(json.getString("isAttrKey"))) {
                            attrKeyList.add(insWfNodeAttr.getAttrValue());
                        }
                    }
                    //GPS
                    if ("gps".equalsIgnoreCase(attr.getAttrType()) && StringUtils.isNotBlank(json.getString("isFlowGPS"))) {
                        if (StringUtil.stringToBoolean(json.getString("isFlowGPS"))) {
                            if (attrValue.indexOf("[") != -1) {
                                String[] gps = attrValue.substring(attrValue.indexOf("[") + 1, attrValue.indexOf("]")).split(",");
                                insWf.setLongitude(gps[1].trim());
                                insWf.setLatitude(gps[0].trim());
                                insWfDao.save(insWf);
                            }
                        }
                        //address
                        if (StringUtils.isNotBlank(json.getString("isFlowAddress"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowAddress"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    attrValue = attrValue.substring(0, attrValue.indexOf("["));
                                }
                                insWf.setAddress(attrValue);
                                insWfDao.save(insWf);
                            }
                        }
                    }
                }

            }
        }

        if (!attrKeyList.isEmpty()) {
            insWf.setFlowDesc(StringUtils.join(attrKeyList.toArray(), ","));
        } else {
            insWf.setFlowDesc(wf.getFlowName());
        }
        insWfDao.update(insWf);

        //流程调度
        genWfSchedule(insWf.getFlowId(), insWf.getInsFlowId(), insWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TONEXT, null);
        return insWf;
    }


    /**
     * 流程节点提交
     *
     * @param insNodeId
     * @param models
     * @param user
     * @return
     * @throws Exception
     */
    public InsWf commitFlow(long insNodeId, Map<String, Object> models, WorkflowUser user) throws Exception {

        InsWfNode insWfNode = insWfNodeDao.get(InsWfNode.class, insNodeId);
        if (insWfNode == null || insWfNode.getNodeState() != WorkflowConstant.FLOW_STATE_TODO) {
            throw new Exception("流程节点实例数据异常");
        }
        InsWf insWf = insWfDao.get(InsWf.class, insWfNode.getInsFlowId());
        if (insWf == null || insWf.getFlowState() != WorkflowConstant.FLOW_STATE_TODO) {
            throw new Exception("流程实例数据异常");
        }

        insWfNode.setNodeState(WorkflowConstant.FLOW_STATE_DONE);
        insWfNode.setReplyResult("Y");
        if (models != null && models.containsKey("replyNote")) {
            insWfNode.setReplyNote((String) models.get("replyNote"));
        }
        insWfNode.setDealUid(user.getUid());
        insWfNode.setDealUname(RedisHelper.getUname(user.getUid()));
        insWfNode.setDealTime(DateUtil.getCalendarCurrentTimestamp());
        insWfNodeDao.update(insWfNode);

        //流程属性
        WfNode node = getWfNodeByNodeId(insWfNode.getNodeId());
        List<WfNodeAttr> attrs = getAttrsByNodeId(node.getNodeId());
        List<InsWfNodeAttr> insAttrs = getInsAttrsByInsFlowId(insWfNode.getInsFlowId());
        for (WfNodeAttr attr : attrs) {
            if (models != null && models.containsKey(attr.getAttrCode())) {
                //不是只读属性，保存当前属性值
                if (!StringUtil.stringToBoolean(attr.getReadonly())) {
                    //查询是否保存过


                    String attrValue = getNodeAttrValue(attr, models);
                    if ("upload".equalsIgnoreCase(attr.getAttrType())) {
                        //获取附件信息
                        JSONArray attrJsonObj = JSON.parseArray(attrValue);
                        if (attrJsonObj != null && !attrJsonObj.isEmpty()) {
                            JSONArray wfResorces = new JSONArray();
                            for (int i = 0; i < attrJsonObj.size(); i++) {
                                if (attrJsonObj != null && attrJsonObj.getJSONObject(i).containsKey("storeSrc") && "TEMP_LOCAL".equals(attrJsonObj.getJSONObject(i).getString("storeSrc"))) {//这里肯定是 TEMP_LOCAL
                                    WfTempResource wfTempResource = JSONObject.toJavaObject(attrJsonObj.getJSONObject(i), WfTempResource.class);
                                    WfResource wfResource = moveTempFileToFileStore(wfTempResource, attr, insWfNode);//处理文件
                                    wfResorces.add(wfResource);
                                }
                            }
                            attrValue = wfResorces.toJSONString();
                        }

                    }


                    InsWfNodeAttr insWfNodeAttr = getInsNodeAttr(insWfNode.getInsFlowId(), insNodeId, attr.getAttrCode());
                    if (insWfNodeAttr == null) {
                        insWfNodeAttr = new InsWfNodeAttr();
                        BeanUtils.copyProperties(insWfNodeAttr, attr);
                        insWfNodeAttr.setInsNodeId(insWfNode.getInsNodeId());
                        insWfNodeAttr.setInsFlowId(insWf.getInsFlowId());
                        insWfNodeAttr.setCreateUid(user.getUid());
                    }
                    insWfNodeAttr.setAttrValue(attrValue);
                    insWfNodeAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                    insWfNodeAttrDao.saveOrUpdate(insWfNodeAttr);

                    if (attr.getIsNodeAttr() != null && !"Y".equals(attr.getIsNodeAttr())) {
                        InsWfNodeAttr insWfAttr = getInsNodeAttr(insWf.getInsFlowId(), -1L, attr.getAttrCode());
                        if (insWfAttr == null) {
                            insWfAttr = new InsWfNodeAttr();
                            BeanUtils.copyProperties(insWfAttr, insWfNodeAttr);
                            insWfAttr.setFlowId(-1L);
                            insWfAttr.setFieldsetId(-1L);
                            insWfAttr.setNodeId(-1L);
                            insWfAttr.setInsNodeId(-1L);
                            insWfAttr.setCreateUid(user.getUid());
                            insWfAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                            insWfAttr.setAttrValue(attrValue);
                            insWfNodeAttrDao.save(insWfAttr);
                        } else {
                            insWfAttr.setCreateUid(user.getUid());
                            insWfAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                            insWfAttr.setAttrValue(attrValue);
                            insWfNodeAttrDao.update(insWfAttr);
                        }
                    }
                    //GPS
                    if (StringUtils.isNotBlank(attr.getAttrExp())) {
                        JSONObject json = JSON.parseObject(attr.getAttrExp());
                        if ("gps".equalsIgnoreCase(attr.getAttrType()) && StringUtils.isNotBlank(json.getString("isFlowGPS"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowGPS"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    String[] gps = attrValue.substring(attrValue.indexOf("[") + 1, attrValue.indexOf("]")).split(",");
                                    insWf.setLongitude(gps[1].trim());
                                    insWf.setLatitude(gps[0].trim());
                                    insWfDao.save(insWf);
                                }
                            }
                        }
                        //address
                        if (StringUtils.isNotBlank(json.getString("isFlowAddress"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowAddress"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    attrValue = attrValue.substring(0, attrValue.indexOf("["));
                                }
                                insWf.setAddress(attrValue);
                                insWfDao.save(insWf);
                            }
                        }
                    }

                } else {//是只读属性，从流程属性中获取属性值，生成新的节点属性
                    InsWfNodeAttr insWfAttr = getInsNodeAttr(insWf.getInsFlowId(), -1L, attr.getAttrCode());
                    if (insWfAttr == null) {
                        continue;
                    }
                    //查询是否保存过
                    InsWfNodeAttr insWfNodeAttr = getInsNodeAttr(insWf.getInsFlowId(), insNodeId, attr.getAttrCode());

                    String attrValue = insWfAttr.getAttrValue();
                    if (insWfNodeAttr == null) {
                        insWfNodeAttr = new InsWfNodeAttr();
                        BeanUtils.copyProperties(insWfNodeAttr, attr);
                        insWfNodeAttr.setInsNodeId(insWfNode.getInsNodeId());
                        insWfNodeAttr.setInsFlowId(insWf.getInsFlowId());
                        insWfNodeAttr.setCreateUid(user.getUid());
                    }
                    insWfNodeAttr.setAttrValue(attrValue);
                    insWfNodeAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                    insWfNodeAttrDao.saveOrUpdate(insWfNodeAttr);

                    //GPS
                    if (StringUtils.isNotBlank(attr.getAttrExp())) {
                        JSONObject json = JSON.parseObject(attr.getAttrExp());
                        if ("gps".equalsIgnoreCase(attr.getAttrType()) && StringUtils.isNotBlank(json.getString("isFlowGPS"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowGPS"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    String[] gps = attrValue.substring(attrValue.indexOf("[") + 1, attrValue.indexOf("]")).split(",");
                                    insWf.setLongitude(gps[1].trim());
                                    insWf.setLatitude(gps[0].trim());
                                    insWfDao.save(insWf);
                                }
                            }
                        }
                        //address
                        if (StringUtils.isNotBlank(json.getString("isFlowAddress"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowAddress"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    attrValue = attrValue.substring(0, attrValue.indexOf("["));
                                }
                                insWf.setAddress(attrValue);
                                insWfDao.save(insWf);
                            }
                        }
                    }
                }

//                if ("upload".equalsIgnoreCase(attr.getAttrType())) {
//                    //获取附件信息
//                    List<WfTempResource> wfTempResourceList = new ArrayList<>();
//                    JSONArray fileResources = JSON.parseArray((String) models.get(attr.getAttrType()));
//                    for (int i = 0; i < fileResources.size(); i++) {
//                        JSONObject fileResource = fileResources.getJSONObject(i);
//                        if (fileResource != null) {
//                            WfTempResource wfTempResource = fileResource.toJavaObject(WfTempResource.class);
//                            wfTempResourceList.add(wfTempResource);
//                        }
//                    }
//                    //保存附件信息
//                    saveWfResources(wfTempResourceList, attr, insWfNode);
//                }
            }
        }

        //流程调度
        finishWfSchedule(insWfNode.getInsFlowId(), insNodeId, insWf.getFlowId());
        return insWf;
    }

    /**
     * 流程节点保存
     *
     * @param insNodeId
     * @param models
     * @param user
     * @return
     * @throws Exception
     */
    public InsWf saveFlow(long insNodeId, Map<String, Object> models, WorkflowUser user) throws Exception {

        InsWfNode insWfNode = insWfNodeDao.get(InsWfNode.class, insNodeId);
        if (insWfNode == null || insWfNode.getNodeState() != WorkflowConstant.FLOW_STATE_TODO) {
            throw new Exception("流程节点实例数据异常");
        }
        InsWf insWf = insWfDao.get(InsWf.class, insWfNode.getInsFlowId());
        if (insWf == null || insWf.getFlowState() != WorkflowConstant.FLOW_STATE_TODO) {
            throw new Exception("流程实例数据异常");
        }
        //流程属性
        WfNode node = getWfNodeByNodeId(insWfNode.getNodeId());
        List<WfNodeAttr> attrs = getAttrsByNodeId(node.getNodeId());
        for (WfNodeAttr attr : attrs) {
            if (models != null && models.containsKey(attr.getAttrCode())) {
                //不是是只读属性，保存当前属性值
                if (!StringUtil.stringToBoolean(attr.getReadonly())) {
                    //查询是否保存过

                    String attrValue = getNodeAttrValue(attr, models);
                    if ("upload".equalsIgnoreCase(attr.getAttrType())) {
                        //获取附件信息
                        JSONArray attrJsonObj = JSON.parseArray(attrValue);
                        if (attrJsonObj != null && !attrJsonObj.isEmpty()) {
                            JSONArray wfResorces = new JSONArray();
                            for (int i = 0; i < attrJsonObj.size(); i++) {
                                if (attrJsonObj != null && attrJsonObj.getJSONObject(i).containsKey("storeSrc") && "TEMP_LOCAL".equals(attrJsonObj.getJSONObject(i).getString("storeSrc"))) {//这里肯定是 TEMP_LOCAL
                                    WfTempResource wfTempResource = JSONObject.toJavaObject(attrJsonObj.getJSONObject(i), WfTempResource.class);
                                    WfResource wfResource = moveTempFileToFileStore(wfTempResource, attr, insWfNode);//处理文件
                                    wfResorces.add(wfResource);
                                }
                            }
                            attrValue = wfResorces.toJSONString();
                        }

                    }


                    InsWfNodeAttr insWfNodeAttr = getInsNodeAttr(insWfNode.getInsFlowId(), insNodeId, attr.getAttrCode());
                    if (insWfNodeAttr == null) {
                        insWfNodeAttr = new InsWfNodeAttr();
                        BeanUtils.copyProperties(insWfNodeAttr, attr);
                        insWfNodeAttr.setInsNodeId(insWfNode.getInsNodeId());
                        insWfNodeAttr.setInsFlowId(insWf.getInsFlowId());
                        insWfNodeAttr.setCreateUid(user.getUid());
                    }
                    insWfNodeAttr.setAttrValue(attrValue);
                    insWfNodeAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                    insWfNodeAttrDao.saveOrUpdate(insWfNodeAttr);

                    if (attr.getIsNodeAttr() != null && !"Y".equals(attr.getIsNodeAttr())) {
                        InsWfNodeAttr insWfAttr = getInsNodeAttr(insWf.getInsFlowId(), -1L, attr.getAttrCode());
                        if (insWfAttr == null) {
                            insWfAttr = new InsWfNodeAttr();
                            BeanUtils.copyProperties(insWfAttr, insWfNodeAttr);
                            insWfAttr.setFlowId(-1L);
                            insWfAttr.setFieldsetId(-1L);
                            insWfAttr.setNodeId(-1L);
                            insWfAttr.setInsNodeId(-1L);
                            insWfAttr.setCreateUid(user.getUid());
                            insWfAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                            insWfAttr.setAttrValue(attrValue);
                            insWfNodeAttrDao.save(insWfAttr);
                        } else {
                            insWfAttr.setCreateUid(user.getUid());
                            insWfAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                            insWfAttr.setAttrValue(attrValue);
                            insWfNodeAttrDao.update(insWfAttr);
                        }
                    }

                    //GPS
                    if (StringUtils.isNotBlank(attr.getAttrExp())) {
                        JSONObject json = JSON.parseObject(attr.getAttrExp());
                        if ("gps".equalsIgnoreCase(attr.getAttrType()) && StringUtils.isNotBlank(json.getString("isFlowGPS"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowGPS"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    String[] gps = attrValue.substring(attrValue.indexOf("[") + 1, attrValue.indexOf("]")).split(",");
                                    insWf.setLongitude(gps[1].trim());
                                    insWf.setLatitude(gps[0].trim());
                                    insWfDao.save(insWf);
                                }
                            }
                        }
                        //address
                        if (StringUtils.isNotBlank(json.getString("isFlowAddress"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowAddress"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    attrValue = attrValue.substring(0, attrValue.indexOf("["));
                                }
                                insWf.setAddress(attrValue);
                                insWfDao.save(insWf);
                            }
                        }
                    }
                } else {//是只读属性，从流程属性中获取属性值，生成新的节点属性
                    InsWfNodeAttr insWfAttr = getInsNodeAttr(insWf.getInsFlowId(), -1L, attr.getAttrCode());
                    if (insWfAttr == null) {
                        continue;
                    }
                    //查询是否保存过
                    InsWfNodeAttr insWfNodeAttr = getInsNodeAttr(insWf.getInsFlowId(), insNodeId, attr.getAttrCode());
                    String attrValue = insWfAttr.getAttrValue();
                    if (insWfNodeAttr == null) {
                        insWfNodeAttr = new InsWfNodeAttr();
                        BeanUtils.copyProperties(insWfNodeAttr, attr);
                        insWfNodeAttr.setInsNodeId(insWfNode.getInsNodeId());
                        insWfNodeAttr.setInsFlowId(insWf.getInsFlowId());
                        insWfNodeAttr.setCreateUid(user.getUid());
                    }
                    insWfNodeAttr.setAttrValue(attrValue);
                    insWfNodeAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());
                    insWfNodeAttrDao.saveOrUpdate(insWfNodeAttr);


                    //GPS
                    if (StringUtils.isNotBlank(attr.getAttrExp())) {
                        JSONObject json = JSON.parseObject(attr.getAttrExp());
                        if ("gps".equalsIgnoreCase(attr.getAttrType()) && StringUtils.isNotBlank(json.getString("isFlowGPS"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowGPS"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    String[] gps = attrValue.substring(attrValue.indexOf("[") + 1, attrValue.indexOf("]")).split(",");
                                    insWf.setLongitude(gps[1].trim());
                                    insWf.setLatitude(gps[0].trim());
                                    insWfDao.save(insWf);
                                }
                            }
                        }
                        //address
                        if (StringUtils.isNotBlank(json.getString("isFlowAddress"))) {
                            if (StringUtil.stringToBoolean(json.getString("isFlowAddress"))) {
                                if (attrValue.indexOf("[") != -1) {
                                    attrValue = attrValue.substring(0, attrValue.indexOf("["));
                                }
                                insWf.setAddress(attrValue);
                                insWfDao.save(insWf);
                            }
                        }
                    }
                }


            }
        }

        return insWf;
    }

    /**
     * 流程节点回退
     *
     * @param insNodeId
     * @return
     * @throws Exception
     */
    public InsWf backFlow(long insNodeId, String replyNote, WorkflowUser user) throws Exception {

        InsWfNode insWfNode = insWfNodeDao.get(InsWfNode.class, insNodeId);
        if (insWfNode == null || insWfNode.getNodeState() != WorkflowConstant.FLOW_STATE_TODO) {
            throw new Exception("流程节点实例数据异常");
        }
        InsWf insWf = insWfDao.get(InsWf.class, insWfNode.getInsFlowId());
        if (insWf == null || insWf.getFlowState() != WorkflowConstant.FLOW_STATE_TODO) {
            throw new Exception("流程实例数据异常");
        }
        //修改当前节点属性值
        insWfNode.setReplyResult("N");
        insWfNode.setReplyNote(replyNote);
        insWfNode.setNodeState(WorkflowConstant.FLOW_STATE_BACK);
        insWfNode.setDealUid(user.getUid());
        insWfNode.setDealUname(RedisHelper.getUname(user.getUid()));
        insWfNode.setDealTime(DateUtil.getCalendarCurrentTimestamp());
        insWfNodeDao.update(insWfNode);

        List<WfNode> lastWfNodes = getLastWfNode(insWfNode.getNodeId());
        for (WfNode nextNode : lastWfNodes) {
            //gen出回退节点实例
            InsWfNode lastInsWfNode = genNextInsNode(insWf, nextNode, false, user.getUid(), null);
            List<WfNodeAttr> attrs = getAttrsByNodeId(lastInsWfNode.getNodeId());
            for (WfNodeAttr attr : attrs) {
                InsWfNodeAttr insWfNodeAttr = new InsWfNodeAttr();
                BeanUtils.copyProperties(insWfNodeAttr, attr);
                InsWfNodeAttr lastInsWfNodeAttr = getInsNodeAttr(insWfNode.getInsFlowId(), insWfNode.getInsNodeId(), attr.getAttrCode());
                if (lastInsWfNodeAttr == null) {
                    continue;
                }
                insWfNodeAttr.setInsFlowId(insWf.getInsFlowId());
                insWfNodeAttr.setUpdateUid(user.getUid());

                insWfNodeAttr.setAttrValue(lastInsWfNodeAttr.getAttrValue());
                insWfNodeAttr.setUpdateTime(DateUtil.getCalendarCurrentTimestamp());

                insWfNodeAttrDao.save(insWfNodeAttr);
            }

            //流程调度
            genWfSchedule(lastInsWfNode.getFlowId(), lastInsWfNode.getInsFlowId(), lastInsWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TODO, null);
        }

        return insWf;
    }

    /**
     * 获取属性的值
     *
     * @param attr
     * @param models
     * @return
     */
    private String getNodeAttrValue(WfNodeAttr attr, Map<String, Object> models) {
        if (models.containsKey(attr.getAttrCode())) {

            if ("Input".equalsIgnoreCase(attr.getAttrType()) || "Select".equalsIgnoreCase(attr.getAttrType()) || "DatePicker".equalsIgnoreCase(attr.getAttrType())) {
                return models.get(attr.getAttrCode()).toString();
            } else if ("Cascader".equalsIgnoreCase(attr.getAttrType()) || "MutliSelect".equalsIgnoreCase(attr.getAttrType()) || "Checkbox".equalsIgnoreCase(attr.getAttrType())) {
                return JSON.toJSONString(models.get(attr.getAttrCode()));
            } else {
                return models.get(attr.getAttrCode()).toString();
            }
        } else {
            return null;
        }

    }

//    private InsWfNodeAttr getOrCrtInsWfNodeAttr(List<InsWfNodeAttr> insAttrs, WfNodeAttr attr) throws InvocationTargetException, IllegalAccessException {
//        InsWfNodeAttr insWfNodeAttr = null;
//        if ("Y".equalsIgnoreCase(attr.getIsNodeAttr())) {//如果是节点属性，直接new
//            insWfNodeAttr = new InsWfNodeAttr();
//            BeanUtils.copyProperties(insWfNodeAttr, attr);
//        } else {
//            for (InsWfNodeAttr insAttr : insAttrs) {
//                if (insAttr.getAttrCode().equals(attr.getAttrCode())) {//如果属性编码符合
//                    if (!"Y".equalsIgnoreCase(attr.getIsNodeAttr()) && insAttr.getNodeId() == -1L) {//且属性不为节点属性，实例属性数据中节点也不是节点属性
//                        insWfNodeAttr = insAttr;
//                    }
//                }
//            }
//            if (insWfNodeAttr == null) {//如果未找到，则new
//                insWfNodeAttr = new InsWfNodeAttr();
//                BeanUtils.copyProperties(insWfNodeAttr, attr);
//
//            }
//        }
//        return insWfNodeAttr;
//    }


    /**
     * 结束流程调度
     *
     * @param insFlowId
     * @param insNodeId
     */
    private void finishWfSchedule(long insFlowId, long insNodeId, long flowId) {
        WfSchedule wfSchedule = getWfSchedule(insFlowId, insNodeId);
        if (wfSchedule == null) {
            wfSchedule = new WfSchedule();
            wfSchedule.setInsFlowId(insFlowId);
            wfSchedule.setInsNodeId(insNodeId);
            wfSchedule.setFlowId(flowId);
            wfSchedule.setSchState(WorkflowConstant.SCH_STATE_TONEXT);
            wfScheduleDao.save(wfSchedule);
        }
        wfSchedule.setSchState(WorkflowConstant.SCH_STATE_TONEXT);
        wfScheduleDao.save(wfSchedule);
    }


    /**
     * 获取待调度的流程调度信息
     *
     * @param rows
     * @return
     */
    public List<WfSchedule> getToNextWfSchedule(int rows) {
        String hql = "from WfSchedule where schState = :schState";
        HashMap params = new HashMap();
        params.put("params", WorkflowConstant.SCH_STATE_TONEXT);
        return wfScheduleDao.find(hql, params, 1, rows);
    }

    /**
     * 获取待调度的自动流程调度信息
     *
     * @param rows
     * @return
     */
    public List<WfSchedule> getAutoTodoWfSchedule(int rows) {
        String hql = "from WfSchedule where schState = :schState";
        HashMap params = new HashMap();
        params.put("schState", WorkflowConstant.SCH_STATE_TONEXT);
        return wfScheduleDao.find(hql, params, 1, rows);
    }

    /**
     * 获取下个任务节点数据
     *
     * @param nodeId
     * @return
     */
    public List<WfNode> getNextWfNode(long nodeId) {
        String sql = "select a.NODE_ID, a.FLOW_ID, a.NODE_NAME, a.NODE_TYPE, a.UID, a.ROLE_ID, a.ORG_ID, a.ORG_CODE, a.TIME_LIMIT, a.NODE_EXP, a.CREATE_TIME ,b.REL_EXP from wfdb.WF_NODE a, wfdb.WF_NODE_REL b where b.NODE_ID1 =:nodeId and b.NODE_ID2 = a.NODE_ID ";
        HashMap params = new HashMap();
        params.put("nodeId", nodeId);
        return wfNodeDao.findEntityBySql(sql, params, WfNode.class);
    }

    /**
     * 获取上个任务节点数据
     *
     * @param nodeId
     * @return
     */
    public List<WfNode> getLastWfNode(long nodeId) {
        String sql = "select a.NODE_ID, a.FLOW_ID, a.NODE_NAME, a.NODE_TYPE, a.UID, a.ROLE_ID, a.ORG_ID, a.ORG_CODE, a.TIME_LIMIT, a.NODE_EXP, a.CREATE_TIME,b.REL_EXP from wfdb.WF_NODE a, wfdb.WF_NODE_REL b where b.NODE_ID2 =:nodeId and b.NODE_ID1 = a.NODE_ID ";
        HashMap params = new HashMap();
        params.put("nodeId", nodeId);
        return wfNodeDao.findEntityBySql(sql, params, WfNode.class);
    }

    /**
     * 获取上个任务节点数据
     *
     * @param nodeId
     * @return
     */
    public List<WfNode> getPreWfNode(long nodeId) {
        String sql = "select a.NODE_ID, a.FLOW_ID, a.NODE_NAME, a.NODE_TYPE, a.UID, a.ROLE_ID, a.ORG_ID, a.ORG_CODE, a.TIME_LIMIT, a.NODE_EXP, a.CREATE_TIME, b.REL_EXP  from wfdb.WF_NODE a, wfdb.WF_NODE_REL b where b.NODE_ID2 =:nodeId and b.NODE_ID1 = a.NODE_ID ";
        HashMap params = new HashMap();
        params.put("nodeId", nodeId);
        return wfNodeDao.findEntityBySql(sql, params, WfNode.class);
    }


    public void processWfSchedule(WfSchedule wfSchedule) {

        long insNodeId = wfSchedule.getInsNodeId();
        long insFlowId = wfSchedule.getInsFlowId();
        InsWfNode insWfnode = getInsWfNodeById(insNodeId);
        try {
            WfNode currentNode = getWfNodeByNodeId(insWfnode.getNodeId()); //START 开始节点；END 结束节点；MANUAL 人工节点; AUTO 自动节点; JUDGE 判断节点; CONDITION 条件节点; AND 聚合节点 */
            InsWf insWf = getInsWfById(insFlowId);
            List<WfNode> nextWfNodes = getNextWfNode(insWfnode.getNodeId());
            if ("JUDGE".equalsIgnoreCase(currentNode.getNodeType())) {//如果当前是判断节点
                String condition = currentNode.getNodeExp();
                if (StringUtils.isBlank(condition)) {
                    throw new Exception("当前判断节点[" + currentNode.getNodeId() + "]判读条件未配置");
                }
                if (StringUtils.isBlank(wfSchedule.getNotes())) {
                    throw new Exception("未获取到上一个节点实例编号");
                }
                Long insWfLastNodeId = Long.parseLong(wfSchedule.getNotes());
                if (NumberUtils.isNotNullOrZero(insWfLastNodeId)) {

                    //获取属性实例
                    List<InsWfNodeAttr> insWfAttrs = getInsAttrsByInsFlowId(insFlowId);
                    HashMap params = new HashMap();
                    for (InsWfNodeAttr attr : insWfAttrs) {
                        params.put(attr.getAttrCode(), attr.getAttrValue());
                    }

                    //获取上一次节点实例
                    List<InsWfNodeAttr> insWfLastNodeAttrs = getInsAttrsByInsNodeId(insWfLastNodeId);
                    for (InsWfNodeAttr attr : insWfLastNodeAttrs) {
                        params.put(attr.getAttrCode(), attr.getAttrValue());
                    }

                    Object result = AviatorEvaluator.execute(condition, params);
                    for (WfNode nextNode : nextWfNodes) {
                        if (result != null && result.toString().equalsIgnoreCase(nextNode.getRelExp())) {
                            if ("END".equalsIgnoreCase(nextNode.getNodeType())) {
                                insWf.setFlowState(WorkflowConstant.FLOW_STATE_DONE);
                                insWf.setDealTime(DateUtil.getCalendarCurrentTimestamp());
                                insWfDao.save(insWf);

                                InsWfNode nextInsWfNode = genNextInsNode(insWf, nextNode, true, insWfnode.getCreateUid(), insWfnode.getCreateUid());
                                nextInsWfNode.setDealTime(DateUtil.getCalendarCurrentTimestamp());
                                insWfNodeDao.save(nextInsWfNode);

                                genWfSchedule(insWf.getFlowId(), insWf.getInsFlowId(), nextInsWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TONEXT, String.valueOf(insNodeId));
                            } else {
                                //流程节点实例
                                InsWfNode insWfNode = genNextInsNode(insWf, nextNode, false, insWfnode.getCreateUid(), null);
                                //下一个节点类型判断
                                if ("JUDGE".equals(nextNode.getNodeType()) || "AUTO".equals(nextNode.getNodeType()) || "END".equals(nextNode.getNodeType())) {
                                    //流程调度
                                    genWfSchedule(insWf.getFlowId(), insWf.getInsFlowId(), insWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TONEXT, String.valueOf(insNodeId));
                                } else {
                                    //流程调度
                                    genWfSchedule(insWf.getFlowId(), insWf.getInsFlowId(), insWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TODO, null);
                                }
                            }
                        }
                    }
                }
            } else {
                for (WfNode nextNode : nextWfNodes) {
                    if ("END".equalsIgnoreCase(nextNode.getNodeType())) {//如果当前是结束节点
                        insWf.setFlowState(WorkflowConstant.FLOW_STATE_DONE);
                        insWf.setDealTime(DateUtil.getCalendarCurrentTimestamp());
                        insWfDao.save(insWf);

                        InsWfNode nextInsWfNode = genNextInsNode(insWf, nextNode, true, insWfnode.getCreateUid(), insWfnode.getCreateUid());
                        nextInsWfNode.setDealTime(DateUtil.getCalendarCurrentTimestamp());
                        insWfNodeDao.save(nextInsWfNode);
                        genWfSchedule(insWf.getFlowId(), insWf.getInsFlowId(), nextInsWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TONEXT, String.valueOf(insNodeId));
                    } else if ("AND".equalsIgnoreCase(nextNode.getNodeType())) {//如果当前是聚合节点
                        InsWfNode nextInsNode = queryInsNode(insWfnode.getInsFlowId(), nextNode.getNodeId(), WorkflowConstant.FLOW_STATE_TODO);//聚合节点是否已经创建
                        if (nextInsNode == null) {//如果没有则创建聚合节点
                            nextInsNode = genNextInsNode(insWf, nextNode, false, insWfnode.getCreateUid(), null);
                            nextInsNode.setReplyResult(String.valueOf(currentNode.getNodeId()));
                        } else {
                            nextInsNode.setReplyResult(nextInsNode.getReplyResult() + "#" + currentNode.getNodeId());
                        }
                        insWfNodeDao.save(nextInsNode);

                        List<WfNode> preWfNodes = getPreWfNode(nextInsNode.getNodeId()); //获取上个节点数据，检查上个节点的流程节点是否都已经完成
                        boolean isAllNodesFinished = true;
                        String[] finishNodeIds = nextInsNode.getReplyResult().split("#");
                        for (WfNode preWfNode : preWfNodes) {
                            boolean isFinished = false;
                            for (String finishNodeId : finishNodeIds) {
                                if (NumberUtils.toLong(finishNodeId, 0) == preWfNode.getNodeId().longValue()) {
                                    isFinished = true;
                                }
                            }
                            if (!isFinished) {
                                isAllNodesFinished = false;
                                break;
                            }
                        }
                        if (isAllNodesFinished) {//如果都完成了
                            commitFlow(nextInsNode.getInsNodeId(), null, new WorkflowUser());
                        }
                    } else {
                        //流程节点实例
                        InsWfNode insWfNode = genNextInsNode(insWf, nextNode, false, insWfnode.getCreateUid(), null);
                        //下一个节点类型判断
                        if ("JUDGE".equals(nextNode.getNodeType()) || "AUTO".equals(nextNode.getNodeType()) || "END".equals(nextNode.getNodeType())) {
                            //流程调度
                            genWfSchedule(insWf.getFlowId(), insWf.getInsFlowId(), insWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TONEXT, String.valueOf(insNodeId));
                        } else {
                            //流程调度
                            genWfSchedule(insWf.getFlowId(), insWf.getInsFlowId(), insWfNode.getInsNodeId(), WorkflowConstant.SCH_STATE_TODO, null);
                        }
                    }
                }
            }
            insWfnode.setNodeState(WorkflowConstant.FLOW_STATE_DONE);
            insWfNodeDao.save(insWfnode);

            wfSchedule.setSchState(WorkflowConstant.SCH_STATE_DONE);
            wfScheduleDao.saveOrUpdate(wfSchedule);
        } catch (
                Exception e)

        {
            String error = e.getMessage();
            insWfnode.setNodeState(WorkflowConstant.FLOW_STATE_ERROR);
            insWfnode.setReplyNote(error);
            insWfNodeDao.save(insWfnode);
        }

    }

    public InsWfNodeAttr getInsNodeAttr(long insFlowId, long insNodeId, String attrCode) {
        String hql = "from InsWfNodeAttr where insFlowId =:insFlowId and insNodeId =:insNodeId and attrCode = :attrCode";
        HashMap params = new HashMap();
        params.put("insFlowId", insFlowId);
        params.put("insNodeId", insNodeId);
        params.put("attrCode", attrCode);
        return insWfNodeAttrDao.get(hql, params);
    }


    private InsWfNode queryInsNode(long insFlowId, long nodeId, long nodeState) {
        String hql = "from InsWfNode where insFlowId =:insFlowId and nodeId =:nodeId and nodeState = :nodeState";
        HashMap params = new HashMap();
        params.put("insFlowId", insFlowId);
        params.put("nodeId", nodeId);
        params.put("nodeState", nodeState);
        return insWfNodeDao.get(hql, params);
    }


    /**
     * 创建并保存下个节点实例数据
     *
     * @param insWf
     * @param nextNode
     * @return
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private InsWfNode genNextInsNode(InsWf insWf, WfNode nextNode, boolean isStart, Long uId, Long dealUid) throws IllegalAccessException, InvocationTargetException {
        InsWfNode insWfNode = new InsWfNode();
        BeanUtils.copyProperties(insWfNode, nextNode);
        insWfNode.setInsFlowId(insWf.getInsFlowId());
        if (isStart) {
            insWfNode.setNodeState(WorkflowConstant.FLOW_STATE_TONEXT);
        } else {
            insWfNode.setNodeState(WorkflowConstant.FLOW_STATE_TODO);
        }
        insWfNode.setPartyId(insWf.getPartyId());
        insWfNode.setFlowName(insWf.getFlowName());
        if (NumberUtils.isNotNullOrZero(uId)) {
            insWfNode.setCreateUid(uId);
            insWfNode.setCreateUname(RedisHelper.getUname(uId));
        }
        if (NumberUtils.isNotNullOrZero(nextNode.getTimeLimit())) {
            insWfNode.setDeadline(DateUtils.addMinutes(new Date(), nextNode.getTimeLimit().intValue()));
        }
        if (NumberUtils.isNotNullOrZero(dealUid)) {
            insWfNode.setDealUid(dealUid);
            insWfNode.setDealUname(RedisHelper.getUname(dealUid));
        }

        UserBasic UserBasic = getUserBasicByUid(insWf.getCreateUid());
        if ("${CURR_ORG_ID}".equals(nextNode.getOrgId())) {
            insWfNode.setOrgId(UserBasic.getOrgId());
        }
        if ("${CURR_ORG_CODE}".equals(nextNode.getOrgCode())) {
            insWfNode.setOrgCode(UserBasic.getOrgCode());
        }
        insWfNodeDao.save(insWfNode);
        return insWfNode;
    }

    /**
     * 创建流程调度数据
     *
     * @param inFlowId
     * @param inInsFlowId
     * @param inInsNodeId
     * @param inSchState
     * @param inNotes
     */
    private void genWfSchedule(Long inFlowId, Long inInsFlowId, Long inInsNodeId, Long inSchState, String inNotes) {
        WfSchedule wfSchedule = new WfSchedule(inFlowId, inInsFlowId, inInsNodeId, inSchState, inNotes);
        wfScheduleDao.save(wfSchedule);
    }

    /**
     * 获取工作流节点信息
     *
     * @return
     */
    public List<InsWfNode> getInsFlowNodesByPage(Long insFlowId, String insFlowDesc, Long partyId, Long createUid, Long uid, Long orgId, String roleIdList, String orgCode, String startTime, String endTime, String deadTime, Integer flowState, Integer nodeState, PageFilter pf) {
        HashMap<String, Object> params = new HashMap<String, Object>();

        StringBuffer hql = new StringBuffer();
        hql.append("select   b.INS_NODE_ID,b.INS_FLOW_ID,b.PRE_INS_NODE_ID,b.NODE_ID,b.FLOW_ID ,a.FLOW_NAME,a.FLOW_DESC,b.NODE_NAME,b.NODE_TYPE ,b.NODE_STATE,b.REPLY_RESULT,b.REPLY_NOTE ,b.STATE ,b.UID ,b.ROLE_ID ,b.ORG_ID ,  b.ORG_CODE,b.DEADLINE ,a.CREATE_UID,a.CREATE_UNAME ,b.CREATE_TIME,b.PARTY_ID ,b.AGENT_UID ,b.DEAL_UID ,b.DEAL_UNAME ,b.DEAL_TIME from wfdb.INS_WF a, wfdb.INS_WF_NODE b where a.INS_FLOW_ID = b.INS_FLOW_ID and a.PARTY_ID = :insPartyId ");
        params.put("insPartyId", partyId);

        hql.append(" and b.NODE_TYPE not in ('JUDGE','AND','AUTO') ");

        if (NumberUtils.isNotNullOrZero(nodeState)) {
            hql.append("and b.NODE_STATE = :nodeState ");
            params.put("nodeState", nodeState);
        } else {
            hql.append("and b.NODE_STATE in (1,9) ");
        }

        if (NumberUtils.isNotNullOrZero(insFlowId)) {
            hql.append("and a.INS_FLOW_ID = :insFlowId ");
            params.put("insFlowId", insFlowId);
        }

        if (StringUtils.isNotBlank(insFlowDesc)) {
            hql.append("and a.FLOW_DESC like :insFlowDesc ");
            params.put("insFlowDesc", "%" + insFlowDesc + "%");
        }

        if (NumberUtils.isNotNullOrZero(createUid)) {
            hql.append("and a.CREATE_UID = :createUid ");
            params.put("createUid", createUid);
        }

        if (NumberUtils.isNotNullOrZero(flowState)) {
            hql.append("and a.FLOW_STATE = :flowState ");
            params.put("flowState", flowState);
        }

        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and b.CREATE_TIME >= :startTime  ");
            params.put("startTime", startTime);
        }
        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and b.CREATE_TIME <= :endTime  ");
            params.put("endTime", endTime);
        }

        if (StringUtils.isNotBlank(deadTime)) {
            hql.append(" and DEADLINE < :deadTime ");
            params.put("deadTime", deadTime);
        }

        StringBuffer roleCondition = new StringBuffer();
        if (NumberUtils.isNotNullOrZero(uid)) {
            roleCondition.append("UID = :uId ");
            params.put("uId", uid);

        }
        if (StringUtils.isNotBlank(roleIdList) && NumberUtils.isNotNullOrZero(orgId)) {
            if (roleCondition.length() > 0) {
                roleCondition.append(" or ");
            }
            roleCondition.append(" (ORG_ID = :orgId and ROLE_ID in (:roleIdList))");
            params.put("orgId", orgId);
            params.put("roleIdList", roleIdList);

        }
        if (StringUtils.isNotBlank(roleIdList) && StringUtils.isNotBlank(orgCode)) {
            if (roleCondition.length() > 0) {
                roleCondition.append(" or ");
            }
            roleCondition.append("(ORG_CODE like :orgCode and ROLE_ID in (:roleIdList))");
            params.put("orgCode", orgCode + "%");
            params.put("roleIdList", roleIdList);
        }

        if (NumberUtils.isNotNullOrZero(uid)) {
            if (roleCondition.length() > 0) {
                roleCondition.append(" or ");
            }
            roleCondition.append("AGENT_UID = :agentUid ");
            params.put("agentUid", uid);
        }

        if (roleCondition.length() > 0) {
            hql.append(" and (").append(roleCondition).append(")");
        }

        hql.append(" order by INS_NODE_ID DESC ");
        return insWfNodeDao.findEntityBySql(hql.toString(), params, InsWfNode.class, pf.getPage(), pf.getRows());
    }


    /**
     * 获取工作流节点信息
     *
     * @return
     */
    public BigInteger countInsFlowNodes(Long insFlowId, String insFlowDesc, Long partyId, Long createUid, Long uid, Long orgId, String roleIdList, String orgCode, String startTime, String endTime, String deadTime, Integer flowState, Integer nodeState) {
        HashMap<String, Object> params = new HashMap<String, Object>();

        StringBuffer hql = new StringBuffer();
        hql.append("select count(*) from wfdb.INS_WF a, wfdb.INS_WF_NODE b where  a.INS_FLOW_ID = b.INS_FLOW_ID and  a.PARTY_ID = :insPartyId ");
        params.put("insPartyId", partyId);

        hql.append(" and b.NODE_TYPE not in ('JUDGE','AND','AUTO') ");

        if (NumberUtils.isNotNullOrZero(nodeState)) {
            hql.append(" and b.NODE_STATE = :nodeState ");
            params.put("nodeState", nodeState);
        } else {
            hql.append(" and b.NODE_STATE in (1,9) ");
        }

        if (NumberUtils.isNotNullOrZero(insFlowId)) {
            hql.append("and a.INS_FLOW_ID = :insFlowId ");
            params.put("insFlowId", insFlowId);
        }

        if (StringUtils.isNotBlank(insFlowDesc)) {
            hql.append("and a.FLOW_DESC like  :insFlowDesc ");
            params.put("insFlowDesc", "%" + insFlowDesc + "%");
        }

        if (NumberUtils.isNotNullOrZero(flowState)) {
            hql.append("and a.FLOW_STATE = :flowState ");
            params.put("flowState", flowState);
        }
        if (NumberUtils.isNotNullOrZero(createUid)) {
            hql.append("and a.CREATE_UID = :createUid ");
            params.put("createUid", createUid);
        }
        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and b.CREATE_TIME >= :startTime  ");
            params.put("startTime", startTime);
        }
        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and b.CREATE_TIME <= :endTime  ");
            params.put("endTime", endTime);
        }

        if (StringUtils.isNotBlank(deadTime)) {
            hql.append(" and DEADLINE < :deadTime ");
            params.put("deadTime", deadTime);
        }

        StringBuffer roleCondition = new StringBuffer();
        if (NumberUtils.isNotNullOrZero(uid)) {
            roleCondition.append("UID = :uId ");
            params.put("uId", uid);

        }
        if (StringUtils.isNotBlank(roleIdList) && NumberUtils.isNotNullOrZero(orgId)) {
            if (roleCondition.length() > 0) {
                roleCondition.append(" or ");
            }
            roleCondition.append(" ( ORG_ID = :orgId and ROLE_ID in ( :roleIdList ))");
            params.put("orgId", orgId);
            params.put("roleIdList", roleIdList);

        }
        if (StringUtils.isNotBlank(roleIdList) && StringUtils.isNotBlank(orgCode)) {
            if (roleCondition.length() > 0) {
                roleCondition.append(" or ");
            }
            roleCondition.append("(ORG_CODE like :orgCode and ROLE_ID in (:roleIdList))");
            params.put("orgCode", orgCode + "%");
            params.put("roleIdList", roleIdList);
        }

        if (NumberUtils.isNotNullOrZero(uid)) {
            if (roleCondition.length() > 0) {
                roleCondition.append(" or ");
            }
            roleCondition.append("AGENT_UID = :agentUid ");
            params.put("agentUid", uid);
        }

        if (roleCondition.length() > 0) {
            hql.append(" and (").append(roleCondition).append(")");
        }

        return insWfNodeDao.countBySql(hql.toString(), params);
    }

    public List<InsWfNode> getInsNodesByInsFlowId(long insFlowId) {
        String hql = "from InsWfNode where INS_FLOW_ID = :insFlowId";

        hql += " and NODE_TYPE not in ('JUDGE','AND','AUTO') ";

        HashMap<String, Object> params = new HashMap<String, Object>();
        params.put("insFlowId", insFlowId);
        return insWfNodeDao.find(hql, params);
    }


    /**
     * 获取工作流信息
     *
     * @return
     */
    public List<InsWf> getInsFlows(Long insFlowId, String insFlowDesc, Long createUid,Long dealUid, String startTime, String endTime, Long flowState,Long nodeState, String orgCode, PageFilter pf) {
        HashMap<String, Object> params = new HashMap<String, Object>();

        StringBuffer hql = new StringBuffer();
        hql.append("SELECT distinct a.* FROM wfdb.INS_WF_NODE b ,wfdb.INS_WF a where a.INS_FLOW_ID = b.INS_FLOW_ID ");

        hql.append(" and b.NODE_TYPE not in ('JUDGE','AND','AUTO') ");

        if (NumberUtils.isNotNullOrZero(createUid)) {
            hql.append("and a.CREATE_UID = :createUid ");
            params.put("createUid", createUid);
        }
        if (NumberUtils.isNotNullOrZero(dealUid)) {
            hql.append("and b.DEAL_UID = :dealUid ");
            params.put("dealUid", dealUid);
        }
        if (NumberUtils.isNotNullOrZero(nodeState)) {
            hql.append("and b.NODE_STATE = :nodeState ");
            params.put("nodeState", nodeState);
        }


        if (NumberUtils.isNotNullOrZero(insFlowId)) {
            hql.append("and a.INS_FLOW_ID = :insFlowId ");
            params.put("insFlowId", insFlowId);
        }

        if (StringUtils.isNotBlank(insFlowDesc)) {
            hql.append("and a.FLOW_DESC like  :insFlowDesc ");
            params.put("insFlowDesc", "%" + insFlowDesc + "%");
        }

        if (NumberUtils.isNotNullOrZero(flowState)) {
            hql.append("and a.FLOW_STATE = :flowState ");
            params.put("flowState", flowState);
        }

        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and a.CREATE_TIME >= :startTime  ");
            params.put("startTime", startTime);
        }
        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and a.CREATE_TIME <= :endTime  ");
            params.put("endTime", endTime);
        }
        if (StringUtils.isNotBlank(orgCode)) {
            hql.append(" and b.ORG_CODE like :orgCode  ");
            params.put("orgCode", orgCode+"%");
        }

        hql.append(" order by INS_FLOW_ID DESC ");
        return insWfDao.findEntityBySql(hql.toString(), params, InsWf.class, pf.getPage(), pf.getRows());
    }

    /**
     * 获取工作流信息
     *
     * @return
     */
    public BigInteger countInsFlows(Long insFlowId, String insFlowDesc, Long createUid,Long dealUid, String startTime, String endTime, Long flowState,Long nodeState, String orgCode) {
        HashMap<String, Object> params = new HashMap<String, Object>();

        StringBuffer hql = new StringBuffer();
        hql.append("SELECT count(distinct a.INS_FLOW_ID) FROM wfdb.INS_WF_NODE b ,wfdb.INS_WF a where a.INS_FLOW_ID = b.INS_FLOW_ID ");

        hql.append(" and b.NODE_TYPE not in ('JUDGE','AND','AUTO') ");

        if (NumberUtils.isNotNullOrZero(createUid)) {
            hql.append("and a.CREATE_UID = :createUid ");
            params.put("createUid", createUid);
        }
        if (NumberUtils.isNotNullOrZero(createUid)) {
            hql.append("and b.DEAL_UID = :dealUid ");
            params.put("dealUid", dealUid);
        }
        if (NumberUtils.isNotNullOrZero(nodeState)) {
            hql.append("and b.NODE_STATE = :nodeState ");
            params.put("nodeState", nodeState);
        }

        if (NumberUtils.isNotNullOrZero(insFlowId)) {
            hql.append("and a.INS_FLOW_ID = :insFlowId ");
            params.put("insFlowId", insFlowId);
        }

        if (StringUtils.isNotBlank(insFlowDesc)) {
            hql.append("and a.FLOW_DESC like  :insFlowDesc ");
            params.put("insFlowDesc", "%" + insFlowDesc + "%");
        }


        if (NumberUtils.isNotNullOrZero(flowState)) {
            hql.append("and a.FLOW_STATE = :flowState ");
            params.put("flowState", flowState);
        }

        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and a.CREATE_TIME >= :startTime  ");
            params.put("startTime", startTime);
        }
        if (StringUtils.isNotBlank(startTime)) {
            hql.append(" and a.CREATE_TIME <= :endTime  ");
            params.put("endTime", endTime);
        }
        if (StringUtils.isNotBlank(orgCode)) {
            hql.append(" and b.ORG_CODE like :orgCode  ");
            params.put("orgCode", orgCode+"%");
        }

        return insWfDao.countBySql(hql.toString(), params);
    }


    @Override
    public WfTempResource saveWfTempResource(WfTempResource wfTempResource, String cfgCode) {

        wfTempResourceDao.save(wfTempResource);

        return wfTempResource;
    }

    public List<WfResource> getWfResources(long insFlowId, long insNodeId, String attrCode) {
        String hql = "from WfResource where insFlowId = :insFlowId and insNodeId = :insNodeId ";
        HashMap params = new HashMap();
        params.put("insFlowId", insFlowId);
        params.put("insNodeId", insNodeId);
        if (StringUtils.isNotBlank(attrCode)) {
            hql += " and attrCode = :attrCode ";
            params.put("attrCode", attrCode);
        } else {
            hql += " and attrCode is null ";
        }
        return wfResourceDao.find(hql, params);
    }

//    /**
//     * 文件移动
//     *
//     * @param fileName
//     * @throws Exception
//     */
//    private void removeFile(String fileName) throws Exception {
//
//        String currentDate = DateUtil.getFormattedDate(new Date(), "yyyyMMdd");
//
//        String tempFile = Configure.getFileTempDir() + "/" + currentDate + "/" + System.getProperty("file.separator") + fileName;
//        File file = new File(tempFile);
//        if (!file.exists()) {
//            throw new Exception("临时文件未找到");
//        }
//
//        String filePath = Configure.getFileDir() + "/" + currentDate + "/";
//        File fileDir = new File(filePath);
//        if (!fileDir.exists()) {
//            fileDir.mkdirs();
//        }
//
//        String newFile = filePath + System.getProperty("file.separator") + fileName;
//        // 转存文件
//        file.renameTo(new File(newFile));
//
//    }

//    public void saveWfResources(WfTempResource wfTempResourceList, WfNodeAttr attr, InsWfNode insWfNode) throws Exception {
//
//        if (wfTempResourceList == null || wfTempResourceList.isEmpty()) {
//            return;
//        }
//
//        EdposResourceConfig resourceConfig = this.getResourceCfgByCode("Upload");
//
//        for (WfTempResource wfTempResource : wfTempResourceList) {
//            //移动附件
//            removeFile(wfTempResource.getResourceName());
//
//            if ("TEMP_LOCAL".equals(wfTempResource.getStoreSrc())) {
//                WfTempResource wfTempResourceFDB = wfTempResourceDao.get(WfTempResource.class, wfTempResource.getResId());
//                if (wfTempResourceFDB != null) {
//                    throw new Exception("临时文件不存在");
//                }
//                WfResource wfResource = new WfResource();
//                BeanUtils.copyProperties(wfResource, wfTempResourceFDB);
//                wfResource.setStoreUrl(resourceConfig.getAttachUrl() + wfResource.getStoreUrl());
//                wfResource.setInsFlowId(insWfNode.getInsFlowId());
//                wfResource.setAttrCode(attr.getAttrCode());
//                wfResource.setStoreSrc("LOCAL");
//                if (attr.getIsNodeAttr() != null && !"Y".equals(attr.getIsNodeAttr())) {
//                    wfResource.setInsNodeId(-1L);
//                } else {
//                    wfResource.setInsNodeId(insWfNode.getInsNodeId());
//                }
//                wfResourceDao.save(wfResource);
//                wfTempResourceDao.delete(wfTempResourceFDB);
//            }
//        }
//    }

    /**
     * 获取资源配置
     *
     * @param code
     * @return
     * @throws Exception
     */
    public ResConfig getResConfig(String code) throws Exception {
        return configDao.get(ResConfig.class, code);
    }

    private WfResource moveTempFileToFileStore(WfTempResource wfTempResource, WfNodeAttr attr, InsWfNode insWfNode) throws Exception {
        ResConfig resourceConfig = this.getResConfig("Upload");
        //移动附件
        String resFilePath = removeFile(wfTempResource);
        WfTempResource wfTempResourceFDB = wfTempResourceDao.get(WfTempResource.class, wfTempResource.getResId());

        WfResource wfResource = new WfResource();
        BeanUtils.copyProperties(wfResource, wfTempResourceFDB);
        wfResource.setStoreUrl(resourceConfig.getAttachUrl() + resFilePath);
        wfResource.setInsFlowId(insWfNode.getInsFlowId());
        wfResource.setAttrCode(attr.getAttrCode());
        wfResource.setStoreSrc("LOCAL");
        if (attr.getIsNodeAttr() != null && !"Y".equals(attr.getIsNodeAttr())) {
            wfResource.setInsNodeId(-1L);
        } else {
            wfResource.setInsNodeId(insWfNode.getInsNodeId());
        }
        wfResourceDao.save(wfResource);
        wfTempResourceDao.delete(wfTempResourceFDB);
        return wfResource;
    }

    private String removeFile(WfTempResource wfTempResource) throws Exception {

        String tempFile = Configure.getFileTempDir() + System.getProperty("file.separator") + wfTempResource.getStoreDate() + System.getProperty("file.separator") + wfTempResource.getResourceName();
        logger.info("tempFile:" + tempFile);
        File file = new File(tempFile);
        if (!file.exists()) {
            throw new Exception("临时文件未找到");
        }

        String filePath = Configure.getFileDir() + System.getProperty("file.separator") + wfTempResource.getStoreDate();
        logger.info("filePath:" + filePath);
        File fileDir = new File(filePath);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
            logger.info("filePath mkdirs:" + filePath);
        }

        String newFilePath = filePath + System.getProperty("file.separator") + wfTempResource.getResourceName();
        logger.info("newFilePath:" + newFilePath);
        // 转存文件
        file.renameTo(new File(newFilePath));

        return newFilePath;
    }

    public InsWfNode transferDealUser(InsWfNode insWfNode, Long agentUid) {
        insWfNode.setAgentUid(agentUid);
        insWfNodeDao.update(insWfNode);
        return insWfNode;
    }

    public UserBasic getUserBasicByUid(long uid) {
        String jsonStr = RedisHelper.getUser(uid);
        UserBasic user = null;
        if (StringUtils.isNotBlank(jsonStr)) {
            user = JSONObject.parseObject(jsonStr, UserBasic.class);
        } else {
            String hql = "from UserBasic where state = 1 and uid = :uid";
            HashMap params = new HashMap();
            params.put("uid", uid);
            user = userDao.get(hql, params);
        }
        return user;
    }
}
